/**
  ******************************************************************************
  * @file    led.c 
  * @author  Thongnh
  * @version V1.0
  * @date    18-07-2011
  * @brief   Main process of led
  ******************************************************************************
  * @attention
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, XICUTELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT 2011 Xicutelectronics</center></h2>
  ******************************************************************************
  */ 

#include "includes.h"

#ifdef USE_LED

/* Private variables ---------------------------------------------------------*/
__IO uint64_t TickCnt = 0;

uint16_t mFrequency = 40;

uint64_t DeboudeSwUpCnt;
uint64_t DeboudeSwDownCnt;

uint8_t SwUpOld;
uint8_t SwDownOld;



void SysTick_Handler(void)
{
    TickCnt++;
}

uint64_t GetTickCount(void)
{
    return TickCnt;
}

bool CheckTick(uint64_t TickBase, const uint64_t Time)
{
    uint64_t CurTick;
    
    CurTick = GetTickCount();
    
    if (CurTick > TickBase)
    {
        if (CurTick >= (TickBase + Time))
        {
            return TRUE;
        }
    }
    else
    {
        if (CurTick >= ((uint64_t)(TickBase + Time)))
        {
            return TRUE;
        }
    }

    return FALSE;
}


/*******************************************************************************
Function name: LedInit
Decription: This function initialize led
Input: None
Output: None
*******************************************************************************/
void LedInit(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef  TIM_OCInitStructure;
    uint16_t freCfg = 24000/mFrequency - 1;
    uint16_t prescalerValue = 0;
    
  /* GPIOA Configuration:TIM3 Channel1 as alternate function push-pull */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

  /* -----------------------------------------------------------------------
    TIM3 Configuration: generate 4 PWM signals with 4 different duty cycles:
    The TIM3CLK frequency is set to SystemCoreClock (Hz), to get TIM3 counter
    clock at 24 MHz the Prescaler is computed as following:
     - Prescaler = (TIM3CLK / TIM3 counter clock) - 1
    SystemCoreClock is set to 72 MHz for Low-density, Medium-density, High-density
    and Connectivity line devices and to 24 MHz for Low-Density Value line and
    Medium-Density Value line devices

    The TIM3 is running at 36 KHz: TIM3 Frequency = TIM3 counter clock/(ARR + 1)
                                                  = 24 MHz / 666 = 36 KHz
    TIM3 Channel1 duty cycle = (TIM3_CCR1/ TIM3_ARR)* 100 = 50%
    TIM3 Channel2 duty cycle = (TIM3_CCR2/ TIM3_ARR)* 100 = 37.5%
    TIM3 Channel3 duty cycle = (TIM3_CCR3/ TIM3_ARR)* 100 = 25%
    TIM3 Channel4 duty cycle = (TIM3_CCR4/ TIM3_ARR)* 100 = 12.5%
  ----------------------------------------------------------------------- */

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

    /* TIM3 enable counter */
    TIM_Cmd(TIM3, ENABLE);
    
    /* Compute the prescaler value */
    prescalerValue = (uint16_t) (SystemCoreClock / 24000000) - 1;
    /* Time base configuration */
    TIM_TimeBaseStructure.TIM_Period = freCfg;
    TIM_TimeBaseStructure.TIM_Prescaler = prescalerValue;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
    
    /* PWM1 Mode configuration: Channel1 */
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = freCfg/2;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    
    TIM_OC1Init(TIM3, &TIM_OCInitStructure);
    
    TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
    
    TIM_ARRPreloadConfig(TIM3, ENABLE);
    
    /* TIM3 enable counter */
    TIM_Cmd(TIM3, ENABLE);


    //initialize SW
    PERPH_CLOCK_CMD_SW;
    INIT_UP;
    INIT_DOWN;
    DeboudeSwUpCnt = DeboudeSwDownCnt = GetTickCount();
    SwUpOld = IN_UP;
    SwDownOld = IN_DOWN;

    INIT_LED;
    LED_OFF;
}

/*******************************************************************************
Function name: LedInit
Decription: This function initialize led
Input: None
Output: None
*******************************************************************************/
void SetFrequency(uint16_t iFre)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef  TIM_OCInitStructure;
    uint16_t freCfg = 24000/iFre - 1;
    uint16_t prescalerValue = (uint16_t) (SystemCoreClock / 24000000) - 1;

    /* TIM3 enable counter */
    TIM_Cmd(TIM3, DISABLE);

    /* Time base configuration */
    TIM_TimeBaseStructure.TIM_Period = freCfg;
    TIM_TimeBaseStructure.TIM_Prescaler = prescalerValue;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
    
    /* PWM1 Mode configuration: Channel1 */
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = freCfg/2;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    
    TIM_OC1Init(TIM3, &TIM_OCInitStructure);
    
    TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
    
    TIM_ARRPreloadConfig(TIM3, ENABLE);
    
    /* TIM3 enable counter */
    TIM_Cmd(TIM3, ENABLE);

    mFrequency = iFre;
}

uint16_t GetFrequency (void)
{
    return (mFrequency);
}


#define LED_TONGLE_TIME         300

/*******************************************************************************
Function name: LedProcess
Decription: This function Process for led
Input: None
Output: None
*******************************************************************************/
void LedProcess(void)
{
    uint8_t bit;

    bit = IN_UP;
    if (SW_ACTIVE == bit)
    {
        if (SwUpOld != bit)
        {
            if (UP_LIMIT > mFrequency) 
            {
                mFrequency++;
                SetFrequency(mFrequency);
                LED_ON;
            }
            SwUpOld = bit;
        }
        DeboudeSwUpCnt = GetTickCount();
    }
    else
    {
        if (SwUpOld != bit)
        {
            if (TRUE == CheckTick(DeboudeSwUpCnt, SW_DEBOUDE_TIME))
            {
                SwUpOld = bit;
                LED_OFF;
            }
        }
    }
    
    bit = IN_DOWN;
    if (SW_ACTIVE == bit)
    {
        if (SwDownOld != bit)
        {
            if (DOWN_LIMIT < mFrequency) 
            {
                mFrequency--;
                SetFrequency(mFrequency);
                LED_ON;
            }
            SwDownOld = bit;
        }
        DeboudeSwDownCnt = GetTickCount();
    }
    else
    {
        if (SwDownOld != bit)
        {
            if (TRUE == CheckTick(DeboudeSwDownCnt, SW_DEBOUDE_TIME))
            {
                SwDownOld = bit;
                LED_OFF;
            }
        }
    }
}

#if 0
/*******************************************************************************
Function name: StrCmp
Decription: Compare two strings
Input: None
Output: 
*******************************************************************************/
bool StrCmp(uint8_t *str1, uint8_t *str2, uint8_t len)
{
    while(len)
    {
        len--;
        if (str1[len] != str2[len])
        {
            return FALSE;
        }
    }
    return TRUE;
}

// chuyen doi tu hex sang ascii
uint8_t htoa(uint8_t d)
{
    uint8_t temp;
    temp = d&0x0F;
    if (temp>9) temp += 7;
    return temp + '0';
}


// chuyen doi tu ascii sang hex
uint8_t atoh(uint8_t c)
{
    uint8_t temp;
    temp = c&0x7F;
    if (temp>'9') temp +=9;
    return temp&0x0F;
}

uint8_t ByteToStr(uint8_t *str, uint8_t byte)
{
    str[0] = htoa(byte>>4);
    str[1] = htoa(byte);
    return 2;
}

uint8_t StrToByte(uint8_t *str)
{
    return (atoh(str[0])<<4) | (atoh(str[1]));
}


uint8_t WordToStr(uint32_t i, uint8_t *str)
{
    str[0] = htoa(i>>12);
    str[1] = htoa(i>>8);
    str[2] = htoa(i>>4);
    str[3] = htoa(i);
    
    return 4;
}

uint16_t StrToWord(uint8_t *str)
{
    return (((uint16_t)atoh(str[0]))<<12) | (((uint16_t)atoh(str[1]))<<8) | (((uint16_t)atoh(str[2]))<<4) | ((uint16_t)atoh(str[3]));
}


uint8_t IntToStr(uint32_t i, uint8_t *str)
{
    str[0] = htoa(i>>28);
    str[1] = htoa(i>>24);
    str[2] = htoa(i>>20);
    str[3] = htoa(i>>16);
    str[4] = htoa(i>>12);
    str[5] = htoa(i>>8);
    str[6] = htoa(i>>4);
    str[7] = htoa(i);
    
    return 8;
}

uint32_t StrToInt(uint8_t *str)
{
    return (((uint32_t)StrToWord(str))<<16) | ((uint32_t)StrToWord(&str[4]));
}
#endif

#endif

// end of file

